﻿using EDC.Common.Exceptions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace EDC.Logic.CSV
{
    /// <summary>
    /// A class for operations on csv file
    /// </summary>
    /// <remarks>
    /// All operations on csv file and memory representation for it
    /// </remarks>    
    public class CSVFile
    {
        /// <summary>
        ///  Initializes a new instance of the CSVFile class with default properties.
        /// </summary>
        public CSVFile()
        {
            InitDefs();
        }

        /// <summary>
        /// Initializes a new instance of the CSVFile class with a specified file name and a separation char.
        /// </summary>
        /// <param name="fileName">file name</param>
        /// <param name="separator">separator</param>
        public CSVFile(string fileName, char separator = ',')
            : this()
        {            
            FileName = fileName;
            Separator = separator;
        }

        /// <summary>
        /// Initializes a new instance of the CSVFile class with a specified file name and a separation char and can open file
        /// </summary>
        /// <param name="fileName">file name</param>
        /// <param name="autoOpen">true - opens specified file</param>
        /// <param name="separator">separator</param>
        /// <remarks>
        /// if autoOpen is true, calls Open()
        /// </remarks>
        public CSVFile(string fileName, bool autoOpen, char separator = ',') 
            : this()
        {
            FileName = fileName;
            Separator = separator;

            if (autoOpen)
            {
                Open();
            }
        }

        private void InitDefs()
        {
            
        }

        /// <summary>
        /// File name
        /// </summary>
        public string FileName { get; set; }

        /// <summary>
        /// File is loaded
        /// </summary>
        public bool IsOpen { get; private set; }

        /// <summary>
        /// Separator char
        /// </summary>
        public char Separator { get; set; }

        /// <summary>
        /// Closes the csv file
        /// </summary>
        public void Close()
        {
            IsOpen = false;
            lines = null;
            FileName = null;
        }

        private List<string> lines = null;

        /// <summary>
        /// Loads data from file
        /// </summary>        
        public void Open()
        {
            if (FileName == null || FileName == string.Empty)
            {
                throw new ArgumentException("Empty param", "FileName");
            }

            lines = new List<string>();

            StreamReader sr = null;

            try
            {
                sr = new StreamReader(FileName, true);                

                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    lines.Add(line);
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                if (sr != null)
                {
                    sr.Dispose();
                }
            }               

            IsOpen = true;            
        }

        /// <summary>
        /// Gets or sets sepcified row value
        /// </summary>
        /// <param name="line">row index</param>
        /// <returns>row data</returns>
        /// <exception cref="NotLoadedDataException">
        /// Throw when data not loaded
        /// </exception>
        /// <exception cref="IndexOutOfRangeException">
        /// Throw when index is less than 0 or greater than rows in file
        /// </exception>
        public string this[int line]
        {
            get
            {
                if (!IsOpen)
                {
                    throw new NotLoadedDataException("Load data first");
                }

                if (line >= lines.Count || line < 0)
                {
                    throw new IndexOutOfRangeException();
                }

                return lines[line];
            }
            set
            {
                if (!IsOpen)
                {
                    throw new NotLoadedDataException("Load data first");
                }

                if (line >= lines.Count || line < 0)
                {
                    throw new IndexOutOfRangeException();
                }

                lines[line] = value;
            }
        }

        /// <summary>
        /// Gets or sets sepcified cell value
        /// </summary>
        /// <param name="line">row index</param>
        /// <param name="column">column index</param>
        /// <returns>cell value</returns>
        /// <exception cref="NotLoadedDataException">
        /// Throw when data not loaded
        /// </exception>
        /// <exception cref="IndexOutOfRangeException">
        /// Throw when index is less than 0 or greater than rows in file or greater than columns count
        /// </exception>
        public string this[int line, int column]
        {
            get
            {
                if (!IsOpen)
                {
                    throw new NotLoadedDataException("Load data first");
                }

                if (line >= lines.Count || line < 0)
                {
                    throw new IndexOutOfRangeException();
                }               

                return lines[line].Split(new char[] { Separator })[column];
            }
            set
            {
                if (!IsOpen)
                {
                    throw new NotLoadedDataException("Load data first");
                }

                if (line >= lines.Count || line < 0)
                {
                    throw new IndexOutOfRangeException();
                }

                string[] arrLine = lines[line].Split(new char[] { Separator });
                arrLine[column] = value;
                lines[line] = string.Join(Separator.ToString(), arrLine);
            }
        }

        /// <summary>
        /// Sets file name and loads data from file
        /// </summary>
        /// <param name="fileName">file name</param>
        public void Open(string fileName)
        {
            FileName = fileName;

            Open();
        }
    }
}
